home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / ASTLoop.c < prev    next >
Text File  |  1994-08-15  |  8KB  |  270 lines

  1. /* ASTLoop.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ASTLoop.h"
  31. #include "ASTExpression.h"
  32. #include "TrashTracker.h"
  33. #include "Memory.h"
  34.  
  35.  
  36. struct ASTLoopRec
  37.     {
  38.         LoopTypes                        KindOfLoop;
  39.         ASTExpressionRec*        ControlExpression;
  40.         ASTExpressionRec*        BodyExpression;
  41.         long                                LineNumber;
  42.     };
  43.  
  44.  
  45. /* create a new loop node */
  46. ASTLoopRec*                    NewLoop(LoopTypes LoopType, struct ASTExpressionRec* ControlExpr,
  47.                                             struct ASTExpressionRec* BodyExpr,
  48.                                             struct TrashTrackRec* TrashTracker, long LineNumber)
  49.     {
  50.         ASTLoopRec*                Loop;
  51.  
  52.         CheckPtrExistence(ControlExpr);
  53.         CheckPtrExistence(BodyExpr);
  54.         CheckPtrExistence(TrashTracker);
  55.         Loop = (ASTLoopRec*)AllocTrackedBlock(sizeof(ASTLoopRec),TrashTracker);
  56.         if (Loop == NIL)
  57.             {
  58.                 return NIL;
  59.             }
  60.         SetTag(Loop,"ASTLoopRec");
  61.  
  62.         Loop->LineNumber = LineNumber;
  63.         Loop->KindOfLoop = LoopType;
  64.         Loop->ControlExpression = ControlExpr;
  65.         Loop->BodyExpression = BodyExpr;
  66.  
  67.         return Loop;
  68.     }
  69.  
  70.  
  71. /* type check the loop node.  this returns eCompileNoError if */
  72. /* everything is ok, and the appropriate type in *ResultingDataType. */
  73. CompileErrors                TypeCheckLoop(DataTypes* ResultingDataType,
  74.                                             ASTLoopRec* Loop, long* ErrorLineNumber,
  75.                                             struct TrashTrackRec* TrashTracker)
  76.     {
  77.         CompileErrors            Error;
  78.         DataTypes                    ConditionalType;
  79.         DataTypes                    BodyType;
  80.  
  81.         CheckPtrExistence(Loop);
  82.         CheckPtrExistence(TrashTracker);
  83.  
  84.         Error = TypeCheckExpression(&ConditionalType,Loop->ControlExpression,
  85.             ErrorLineNumber,TrashTracker);
  86.         if (Error != eCompileNoError)
  87.             {
  88.                 return Error;
  89.             }
  90.         if (ConditionalType != eBoolean)
  91.             {
  92.                 *ErrorLineNumber = Loop->LineNumber;
  93.                 return eCompileConditionalMustBeBoolean;
  94.             }
  95.  
  96.         Error = TypeCheckExpression(&BodyType,Loop->BodyExpression,ErrorLineNumber,
  97.             TrashTracker);
  98.         if (Error != eCompileNoError)
  99.             {
  100.                 return Error;
  101.             }
  102.  
  103.         *ResultingDataType = BodyType;
  104.         return eCompileNoError;
  105.     }
  106.  
  107.  
  108. /* generate code for a loop. returns True if successful, or False if it fails. */
  109. MyBoolean                        CodeGenLoop(struct PcodeRec* FuncCode,
  110.                                             long* StackDepthParam, ASTLoopRec* Loop)
  111.     {
  112.         long                            StackDepth;
  113.         long                            WhileBranchPatchupLocation EXECUTE(= -1);
  114.         long                            LoopBackAgainLocation;
  115.  
  116.         CheckPtrExistence(FuncCode);
  117.         CheckPtrExistence(Loop);
  118.         StackDepth = *StackDepthParam;
  119.  
  120.         /* this is the loopie thing.  the only real difference between a while and */
  121.         /* a repeat loop is that the while has an extra branch to the test. */
  122.         /* repeat loop: */
  123.         /*  - push default return value */
  124.         /*  - pop previous value */
  125.         /*  - evaluate body */
  126.         /*  - perform test */
  127.         /*  - branch if we keep looping to the pop previous value point */
  128.         /* while loop: */
  129.         /*  - push default return value */
  130.         /*  - jump to the test */
  131.         /*  - pop previous value */
  132.         /*  - evaluate body */
  133.         /*  - perform test */
  134.         /*  - branch if we keep looping to the pop previous value point */
  135.  
  136.         /* push the default value -- same type as the body expression has */
  137.         switch (GetExpressionsResultantType(Loop->BodyExpression))
  138.             {
  139.                 default:
  140.                     EXECUTE(PRERR(ForceAbort,"CodeGenLoop:  bad type of body expression"));
  141.                     break;
  142.                 case eBoolean:
  143.                 case eInteger:
  144.                 case eFixed:
  145.                     if (!AddPcodeInstruction(FuncCode,epLoadImmediateInteger,NIL))
  146.                         {
  147.                             return False;
  148.                         }
  149.                     if (!AddPcodeOperandInteger(FuncCode,0))
  150.                         {
  151.                             return False;
  152.                         }
  153.                     break;
  154.                 case eFloat:
  155.                     if (!AddPcodeInstruction(FuncCode,epLoadImmediateFloat,NIL))
  156.                         {
  157.                             return False;
  158.                         }
  159.                     if (!AddPcodeOperandFloat(FuncCode,0))
  160.                         {
  161.                             return False;
  162.                         }
  163.                     break;
  164.                 case eDouble:
  165.                     if (!AddPcodeInstruction(FuncCode,epLoadImmediateDouble,NIL))
  166.                         {
  167.                             return False;
  168.                         }
  169.                     if (!AddPcodeOperandDouble(FuncCode,0))
  170.                         {
  171.                             return False;
  172.                         }
  173.                     break;
  174.                 case eArrayOfBoolean:
  175.                 case eArrayOfInteger:
  176.                 case eArrayOfFloat:
  177.                 case eArrayOfDouble:
  178.                 case eArrayOfFixed:
  179.                     if (!AddPcodeInstruction(FuncCode,epLoadImmediateNILArray,NIL))
  180.                         {
  181.                             return False;
  182.                         }
  183.                     break;
  184.             }
  185.         StackDepth += 1;
  186.         ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
  187.             "CodeGenLoop:  stack depth error after pushing default value"));
  188.  
  189.         /* if loop is a head-tested loop (while loop) then insert extra branch */
  190.         if ((Loop->KindOfLoop == eLoopWhileDo) || (Loop->KindOfLoop == eLoopUntilDo))
  191.             {
  192.                 if (!AddPcodeInstruction(FuncCode,epBranchUnconditional,
  193.                     &WhileBranchPatchupLocation))
  194.                     {
  195.                         return False;
  196.                     }
  197.                 if (!AddPcodeOperandInteger(FuncCode,-1/*target unknown*/))
  198.                     {
  199.                         return False;
  200.                     }
  201.             }
  202.  
  203.         /* remember this address! */
  204.         LoopBackAgainLocation = PcodeGetNextAddress(FuncCode);
  205.  
  206.         /* pop previous result */
  207.         if (!AddPcodeInstruction(FuncCode,epStackPop,NIL))
  208.             {
  209.                 return False;
  210.             }
  211.         StackDepth -= 1;
  212.         ERROR(StackDepth != *StackDepthParam,PRERR(ForceAbort,
  213.             "CodeGenLoop:  stack depth error after popping previous"));
  214.  
  215.         /* evaluate the body */
  216.         if (!CodeGenExpression(FuncCode,&StackDepth,Loop->BodyExpression))
  217.             {
  218.                 return False;
  219.             }
  220.         ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
  221.             "CodeGenLoop:  stack depth error after evaluating body"));
  222.  
  223.         /* patch up the while branch */
  224.         if ((Loop->KindOfLoop == eLoopWhileDo) || (Loop->KindOfLoop == eLoopUntilDo))
  225.             {
  226.                 ResolvePcodeBranch(FuncCode,WhileBranchPatchupLocation,
  227.                     PcodeGetNextAddress(FuncCode));
  228.             }
  229.  
  230.         /* evaluate the test */
  231.         if (!CodeGenExpression(FuncCode,&StackDepth,Loop->ControlExpression))
  232.             {
  233.                 return False;
  234.             }
  235.         ERROR(StackDepth != *StackDepthParam + 2,PRERR(ForceAbort,
  236.             "CodeGenLoop:  stack depth error after evaluating control"));
  237.  
  238.         /* do the appropriate branch */
  239.         if ((Loop->KindOfLoop == eLoopWhileDo) || (Loop->KindOfLoop == eLoopDoWhile))
  240.             {
  241.                 /* "while do" and "do while" need a branch if true conditional */
  242.                 if (!AddPcodeInstruction(FuncCode,epBranchIfNotZero,NIL))
  243.                     {
  244.                         return False;
  245.                     }
  246.                 if (!AddPcodeOperandInteger(FuncCode,LoopBackAgainLocation))
  247.                     {
  248.                         return False;
  249.                     }
  250.             }
  251.          else
  252.             {
  253.                 /* "until do" and "do until" need a branch if false conditional */
  254.                 if (!AddPcodeInstruction(FuncCode,epBranchIfZero,NIL))
  255.                     {
  256.                         return False;
  257.                     }
  258.                 if (!AddPcodeOperandInteger(FuncCode,LoopBackAgainLocation))
  259.                     {
  260.                         return False;
  261.                     }
  262.             }
  263.         StackDepth -= 1;
  264.         ERROR(StackDepth != *StackDepthParam + 1,PRERR(ForceAbort,
  265.             "CodeGenLoop:  stack depth error after control branch"));
  266.  
  267.         *StackDepthParam = StackDepth;
  268.         return True;
  269.     }
  270.